home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / Mail / cmd3.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-02-08  |  12.5 KB  |  698 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. #ifndef lint
  19. static char sccsid[] = "%W% (Berkeley) %G%";
  20. #endif /* not lint */
  21.  
  22. #include "rcv.h"
  23.  
  24. /*
  25.  * Mail -- a mail program
  26.  *
  27.  * Still more user commands.
  28.  */
  29.  
  30. /*
  31.  * Process a shell escape by saving signals, ignoring signals,
  32.  * and forking a sh -c
  33.  */
  34. shell(str)
  35.     char *str;
  36. {
  37.     int (*sigint)() = signal(SIGINT, SIG_IGN);
  38.     char *shell;
  39.     char cmd[BUFSIZ];
  40.  
  41.     (void) strcpy(cmd, str);
  42.     if (bangexp(cmd) < 0)
  43.         return 1;
  44.     if ((shell = value("SHELL")) == NOSTR)
  45.         shell = SHELL;
  46.     (void) run_command(shell, 0, -1, -1, "-c", cmd, NOSTR);
  47.     (void) signal(SIGINT, sigint);
  48.     printf("!\n");
  49.     return 0;
  50. }
  51.  
  52. /*
  53.  * Fork an interactive shell.
  54.  */
  55. /*ARGSUSED*/
  56. dosh(str)
  57.     char *str;
  58. {
  59.     int (*sigint)() = signal(SIGINT, SIG_IGN);
  60.     char *shell;
  61.  
  62.     if ((shell = value("SHELL")) == NOSTR)
  63.         shell = SHELL;
  64.     (void) run_command(shell, 0, -1, -1, NOSTR);
  65.     (void) signal(SIGINT, sigint);
  66.     putchar('\n');
  67.     return 0;
  68. }
  69.  
  70. /*
  71.  * Expand the shell escape by expanding unescaped !'s into the
  72.  * last issued command where possible.
  73.  */
  74.  
  75. char    lastbang[128];
  76.  
  77. bangexp(str)
  78.     char *str;
  79. {
  80.     char bangbuf[BUFSIZ];
  81.     register char *cp, *cp2;
  82.     register int n;
  83.     int changed = 0;
  84.  
  85.     cp = str;
  86.     cp2 = bangbuf;
  87.     n = BUFSIZ;
  88.     while (*cp) {
  89.         if (*cp == '!') {
  90.             if (n < strlen(lastbang)) {
  91. overf:
  92.                 printf("Command buffer overflow\n");
  93.                 return(-1);
  94.             }
  95.             changed++;
  96.             strcpy(cp2, lastbang);
  97.             cp2 += strlen(lastbang);
  98.             n -= strlen(lastbang);
  99.             cp++;
  100.             continue;
  101.         }
  102.         if (*cp == '\\' && cp[1] == '!') {
  103.             if (--n <= 1)
  104.                 goto overf;
  105.             *cp2++ = '!';
  106.             cp += 2;
  107.             changed++;
  108.         }
  109.         if (--n <= 1)
  110.             goto overf;
  111.         *cp2++ = *cp++;
  112.     }
  113.     *cp2 = 0;
  114.     if (changed) {
  115.         printf("!%s\n", bangbuf);
  116.         fflush(stdout);
  117.     }
  118.     strcpy(str, bangbuf);
  119.     strncpy(lastbang, bangbuf, 128);
  120.     lastbang[127] = 0;
  121.     return(0);
  122. }
  123.  
  124. /*
  125.  * Print out a nice help message from some file or another.
  126.  */
  127.  
  128. help()
  129. {
  130.     register c;
  131.     register FILE *f;
  132.  
  133.     if ((f = fopen(HELPFILE, "r")) == NULL) {
  134.         perror(HELPFILE);
  135.         return(1);
  136.     }
  137.     while ((c = getc(f)) != EOF)
  138.         putchar(c);
  139.     fclose(f);
  140.     return(0);
  141. }
  142.  
  143. /*
  144.  * Change user's working directory.
  145.  */
  146. schdir(arglist)
  147.     char **arglist;
  148. {
  149.     char *cp;
  150.  
  151.     if (*arglist == NOSTR)
  152.         cp = homedir;
  153.     else
  154.         if ((cp = expand(*arglist)) == NOSTR)
  155.             return(1);
  156.     if (chdir(cp) < 0) {
  157.         perror(cp);
  158.         return(1);
  159.     }
  160.     return 0;
  161. }
  162.  
  163. respond(msgvec)
  164.     int *msgvec;
  165. {
  166.     if (value("Replyall") == NOSTR)
  167.         return (_respond(msgvec));
  168.     else
  169.         return (_Respond(msgvec));
  170. }
  171.  
  172. /*
  173.  * Reply to a list of messages.  Extract each name from the
  174.  * message header and send them off to mail1()
  175.  */
  176. _respond(msgvec)
  177.     int *msgvec;
  178. {
  179.     struct message *mp;
  180.     char *cp, *rcv, *replyto;
  181.     char **ap;
  182.     struct name *np;
  183.     struct header head;
  184.  
  185.     if (msgvec[1] != 0) {
  186.         printf("Sorry, can't reply to multiple messages at once\n");
  187.         return(1);
  188.     }
  189.     mp = &message[msgvec[0] - 1];
  190.     touch(mp);
  191.     dot = mp;
  192.     if ((rcv = skin(hfield("from", mp))) == NOSTR)
  193.         rcv = skin(nameof(mp, 1));
  194.     if ((replyto = skin(hfield("reply-to", mp))) != NOSTR)
  195.         np = extract(replyto, GTO);
  196.     else if ((cp = skin(hfield("to", mp))) != NOSTR)
  197.         np = extract(cp, GTO);
  198.     else
  199.         np = NIL;
  200.     np = elide(np);
  201.     /*
  202.      * Delete my name from the reply list,
  203.      * and with it, all my alternate names.
  204.      */
  205.     np = delname(np, myname);
  206.     if (altnames)
  207.         for (ap = altnames; *ap; ap++)
  208.             np = delname(np, *ap);
  209.     if (np != NIL && replyto == NOSTR)
  210.         np = cat(np, extract(rcv, GTO));
  211.     else if (np == NIL) {
  212.         if (replyto != NOSTR)
  213.             printf("Empty reply-to field -- replying to author\n");
  214.         np = extract(rcv, GTO);
  215.     }
  216.     head.h_to = np;
  217.     if ((head.h_subject = hfield("subject", mp)) == NOSTR)
  218.         head.h_subject = hfield("subj", mp);
  219.     head.h_subject = reedit(head.h_subject);
  220.     if (replyto == NOSTR && (cp = skin(hfield("cc", mp))) != NOSTR) {
  221.         np = elide(extract(cp, GCC));
  222.         np = delname(np, myname);
  223.         if (altnames != 0)
  224.             for (ap = altnames; *ap; ap++)
  225.                 np = delname(np, *ap);
  226.         head.h_cc = np;
  227.     } else
  228.         head.h_cc = NIL;
  229.     head.h_bcc = NIL;
  230.     head.h_smopts = NIL;
  231.     mail1(&head, 1);
  232.     return(0);
  233. }
  234.  
  235. /*
  236.  * Modify the subject we are replying to to begin with Re: if
  237.  * it does not already.
  238.  */
  239. char *
  240. reedit(subj)
  241.     register char *subj;
  242. {
  243.     char *newsubj;
  244.  
  245.     if (subj == NOSTR)
  246.         return NOSTR;
  247.     if ((subj[0] == 'r' || subj[0] == 'R') &&
  248.         (subj[1] == 'e' || subj[1] == 'E') &&
  249.         subj[2] == ':')
  250.         return subj;
  251.     newsubj = salloc(strlen(subj) + 5);
  252.     strcpy(newsubj, "Re: ");
  253.     strcpy(newsubj + 4, subj);
  254.     return newsubj;
  255. }
  256.  
  257. /*
  258.  * Preserve the named messages, so that they will be sent
  259.  * back to the system mailbox.
  260.  */
  261.  
  262. preserve(msgvec)
  263.     int *msgvec;
  264. {
  265.     register struct message *mp;
  266.     register int *ip, mesg;
  267.  
  268.     if (edit) {
  269.         printf("Cannot \"preserve\" in edit mode\n");
  270.         return(1);
  271.     }
  272.     for (ip = msgvec; *ip != NULL; ip++) {
  273.         mesg = *ip;
  274.         mp = &message[mesg-1];
  275.         mp->m_flag |= MPRESERVE;
  276.         mp->m_flag &= ~MBOX;
  277.         dot = mp;
  278.     }
  279.     return(0);
  280. }
  281.  
  282. /*
  283.  * Mark all given messages as unread.
  284.  */
  285. unread(msgvec)
  286.     int    msgvec[];
  287. {
  288.     register int *ip;
  289.  
  290.     for (ip = msgvec; *ip != NULL; ip++) {
  291.         dot = &message[*ip-1];
  292.         dot->m_flag &= ~(MREAD|MTOUCH);
  293.         dot->m_flag |= MSTATUS;
  294.     }
  295.     return(0);
  296. }
  297.  
  298. /*
  299.  * Print the size of each message.
  300.  */
  301.  
  302. messize(msgvec)
  303.     int *msgvec;
  304. {
  305.     register struct message *mp;
  306.     register int *ip, mesg;
  307.  
  308.     for (ip = msgvec; *ip != NULL; ip++) {
  309.         mesg = *ip;
  310.         mp = &message[mesg-1];
  311.         printf("%d: %d/%ld\n", mesg, mp->m_lines, mp->m_size);
  312.     }
  313.     return(0);
  314. }
  315.  
  316. /*
  317.  * Quit quickly.  If we are sourcing, just pop the input level
  318.  * by returning an error.
  319.  */
  320.  
  321. rexit(e)
  322. {
  323.     if (sourcing)
  324.         return(1);
  325.     exit(e);
  326.     /*NOTREACHED*/
  327. }
  328.  
  329. /*
  330.  * Set or display a variable value.  Syntax is similar to that
  331.  * of csh.
  332.  */
  333.  
  334. set(arglist)
  335.     char **arglist;
  336. {
  337.     register struct var *vp;
  338.     register char *cp, *cp2;
  339.     char varbuf[BUFSIZ], **ap, **p;
  340.     int errs, h, s;
  341.  
  342.     if (*arglist == NOSTR) {
  343.         for (h = 0, s = 1; h < HSHSIZE; h++)
  344.             for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
  345.                 s++;
  346.         ap = (char **) salloc(s * sizeof *ap);
  347.         for (h = 0, p = ap; h < HSHSIZE; h++)
  348.             for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
  349.                 *p++ = vp->v_name;
  350.         *p = NOSTR;
  351.         sort(ap);
  352.         for (p = ap; *p != NOSTR; p++)
  353.             printf("%s\t%s\n", *p, value(*p));
  354.         return(0);
  355.     }
  356.     errs = 0;
  357.     for (ap = arglist; *ap != NOSTR; ap++) {
  358.         cp = *ap;
  359.         cp2 = varbuf;
  360.         while (*cp != '=' && *cp != '\0')
  361.             *cp2++ = *cp++;
  362.         *cp2 = '\0';
  363.         if (*cp == '\0')
  364.             cp = "";
  365.         else
  366.             cp++;
  367.         if (equal(varbuf, "")) {
  368.             printf("Non-null variable name required\n");
  369.             errs++;
  370.             continue;
  371.         }
  372.         assign(varbuf, cp);
  373.     }
  374.     return(errs);
  375. }
  376.  
  377. /*
  378.  * Unset a bunch of variable values.
  379.  */
  380.  
  381. unset(arglist)
  382.     char **arglist;
  383. {
  384.     register struct var *vp, *vp2;
  385.     int errs, h;
  386.     char **ap;
  387.  
  388.     errs = 0;
  389.     for (ap = arglist; *ap != NOSTR; ap++) {
  390.         if ((vp2 = lookup(*ap)) == NOVAR) {
  391.             if (!sourcing) {
  392.                 printf("\"%s\": undefined variable\n", *ap);
  393.                 errs++;
  394.             }
  395.             continue;
  396.         }
  397.         h = hash(*ap);
  398.         if (vp2 == variables[h]) {
  399.             variables[h] = variables[h]->v_link;
  400.             vfree(vp2->v_name);
  401.             vfree(vp2->v_value);
  402.             cfree((char *)vp2);
  403.             continue;
  404.         }
  405.         for (vp = variables[h]; vp->v_link != vp2; vp = vp->v_link)
  406.             ;
  407.         vp->v_link = vp2->v_link;
  408.         vfree(vp2->v_name);
  409.         vfree(vp2->v_value);
  410.         cfree((char *) vp2);
  411.     }
  412.     return(errs);
  413. }
  414.  
  415. /*
  416.  * Put add users to a group.
  417.  */
  418.  
  419. group(argv)
  420.     char **argv;
  421. {
  422.     register struct grouphead *gh;
  423.     register struct group *gp;
  424.     register int h;
  425.     int s;
  426.     char **ap, *gname, **p;
  427.  
  428.     if (*argv == NOSTR) {
  429.         for (h = 0, s = 1; h < HSHSIZE; h++)
  430.             for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
  431.                 s++;
  432.         ap = (char **) salloc(s * sizeof *ap);
  433.         for (h = 0, p = ap; h < HSHSIZE; h++)
  434.             for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
  435.                 *p++ = gh->g_name;
  436.         *p = NOSTR;
  437.         sort(ap);
  438.         for (p = ap; *p != NOSTR; p++)
  439.             printgroup(*p);
  440.         return(0);
  441.     }
  442.     if (argv[1] == NOSTR) {
  443.         printgroup(*argv);
  444.         return(0);
  445.     }
  446.     gname = *argv;
  447.     h = hash(gname);
  448.     if ((gh = findgroup(gname)) == NOGRP) {
  449.         gh = (struct grouphead *) calloc(sizeof *gh, 1);
  450.         gh->g_name = vcopy(gname);
  451.         gh->g_list = NOGE;
  452.         gh->g_link = groups[h];
  453.         groups[h] = gh;
  454.     }
  455.  
  456.     /*
  457.      * Insert names from the command list into the group.
  458.      * Who cares if there are duplicates?  They get tossed
  459.      * later anyway.
  460.      */
  461.  
  462.     for (ap = argv+1; *ap != NOSTR; ap++) {
  463.         gp = (struct group *) calloc(sizeof *gp, 1);
  464.         gp->ge_name = vcopy(*ap);
  465.         gp->ge_link = gh->g_list;
  466.         gh->g_list = gp;
  467.     }
  468.     return(0);
  469. }
  470.  
  471. /*
  472.  * Sort the passed string vecotor into ascending dictionary
  473.  * order.
  474.  */
  475.  
  476. sort(list)
  477.     char **list;
  478. {
  479.     register char **ap;
  480.     int diction();
  481.  
  482.     for (ap = list; *ap != NOSTR; ap++)
  483.         ;
  484.     if (ap-list < 2)
  485.         return;
  486.     qsort((char *)list, ap-list, sizeof *list, diction);
  487. }
  488.  
  489. /*
  490.  * Do a dictionary order comparison of the arguments from
  491.  * qsort.
  492.  */
  493.  
  494. diction(a, b)
  495.     register char **a, **b;
  496. {
  497.     return(strcmp(*a, *b));
  498. }
  499.  
  500. /*
  501.  * The do nothing command for comments.
  502.  */
  503.  
  504. /*ARGSUSED*/
  505. null(e)
  506. {
  507.     return 0;
  508. }
  509.  
  510. /*
  511.  * Change to another file.  With no argument, print information about
  512.  * the current file.
  513.  */
  514. file(argv)
  515.     register char **argv;
  516. {
  517.  
  518.     if (argv[0] == NOSTR) {
  519.         newfileinfo();
  520.         return 0;
  521.     }
  522.     if (setfile(*argv) < 0)
  523.         return 1;
  524.     announce();
  525.     return 0;
  526. }
  527.  
  528. /*
  529.  * Expand file names like echo
  530.  */
  531. echo(argv)
  532.     char **argv;
  533. {
  534.     register char **ap;
  535.     register char *cp;
  536.  
  537.     for (ap = argv; *ap != NOSTR; ap++) {
  538.         cp = *ap;
  539.         if ((cp = expand(cp)) != NOSTR) {
  540.             if (ap != argv)
  541.                 putchar(' ');
  542.             printf("%s", cp);
  543.         }
  544.     }
  545.     putchar('\n');
  546.     return 0;
  547. }
  548.  
  549. Respond(msgvec)
  550.     int *msgvec;
  551. {
  552.     if (value("Replyall") == NOSTR)
  553.         return (_Respond(msgvec));
  554.     else
  555.         return (_respond(msgvec));
  556. }
  557.  
  558. /*
  559.  * Reply to a series of messages by simply mailing to the senders
  560.  * and not messing around with the To: and Cc: lists as in normal
  561.  * reply.
  562.  */
  563. _Respond(msgvec)
  564.     int msgvec[];
  565. {
  566.     struct header head;
  567.     struct message *mp;
  568.     register int *ap;
  569.     register char *cp;
  570.  
  571.     head.h_to = NIL;
  572.     for (ap = msgvec; *ap != 0; ap++) {
  573.         mp = &message[*ap - 1];
  574.         touch(mp);
  575.         dot = mp;
  576.         if ((cp = skin(hfield("from", mp))) == NOSTR)
  577.             cp = skin(nameof(mp, 2));
  578.         head.h_to = cat(head.h_to, extract(cp, GTO));
  579.     }
  580.     if (head.h_to == NIL)
  581.         return 0;
  582.     mp = &message[msgvec[0] - 1];
  583.     if ((head.h_subject = hfield("subject", mp)) == NOSTR)
  584.         head.h_subject = hfield("subj", mp);
  585.     head.h_subject = reedit(head.h_subject);
  586.     head.h_cc = NIL;
  587.     head.h_bcc = NIL;
  588.     head.h_smopts = NIL;
  589.     mail1(&head, 1);
  590.     return 0;
  591. }
  592.  
  593. /*
  594.  * Conditional commands.  These allow one to parameterize one's
  595.  * .mailrc and do some things if sending, others if receiving.
  596.  */
  597.  
  598. ifcmd(argv)
  599.     char **argv;
  600. {
  601.     register char *cp;
  602.  
  603.     if (cond != CANY) {
  604.         printf("Illegal nested \"if\"\n");
  605.         return(1);
  606.     }
  607.     cond = CANY;
  608.     cp = argv[0];
  609.     switch (*cp) {
  610.     case 'r': case 'R':
  611.         cond = CRCV;
  612.         break;
  613.  
  614.     case 's': case 'S':
  615.         cond = CSEND;
  616.         break;
  617.  
  618.     default:
  619.         printf("Unrecognized if-keyword: \"%s\"\n", cp);
  620.         return(1);
  621.     }
  622.     return(0);
  623. }
  624.  
  625. /*
  626.  * Implement 'else'.  This is pretty simple -- we just
  627.  * flip over the conditional flag.
  628.  */
  629.  
  630. elsecmd()
  631. {
  632.  
  633.     switch (cond) {
  634.     case CANY:
  635.         printf("\"Else\" without matching \"if\"\n");
  636.         return(1);
  637.  
  638.     case CSEND:
  639.         cond = CRCV;
  640.         break;
  641.  
  642.     case CRCV:
  643.         cond = CSEND;
  644.         break;
  645.  
  646.     default:
  647.         printf("Mail's idea of conditions is screwed up\n");
  648.         cond = CANY;
  649.         break;
  650.     }
  651.     return(0);
  652. }
  653.  
  654. /*
  655.  * End of if statement.  Just set cond back to anything.
  656.  */
  657.  
  658. endifcmd()
  659. {
  660.  
  661.     if (cond == CANY) {
  662.         printf("\"Endif\" without matching \"if\"\n");
  663.         return(1);
  664.     }
  665.     cond = CANY;
  666.     return(0);
  667. }
  668.  
  669. /*
  670.  * Set the list of alternate names.
  671.  */
  672. alternates(namelist)
  673.     char **namelist;
  674. {
  675.     register int c;
  676.     register char **ap, **ap2, *cp;
  677.  
  678.     c = argcount(namelist) + 1;
  679.     if (c == 1) {
  680.         if (altnames == 0)
  681.             return(0);
  682.         for (ap = altnames; *ap; ap++)
  683.             printf("%s ", *ap);
  684.         printf("\n");
  685.         return(0);
  686.     }
  687.     if (altnames != 0)
  688.         cfree((char *) altnames);
  689.     altnames = (char **) calloc((unsigned) c, sizeof (char *));
  690.     for (ap = namelist, ap2 = altnames; *ap; ap++, ap2++) {
  691.         cp = (char *) calloc((unsigned) strlen(*ap) + 1, sizeof (char));
  692.         strcpy(cp, *ap);
  693.         *ap2 = cp;
  694.     }
  695.     *ap2 = 0;
  696.     return(0);
  697. }
  698.